#ifndef __COMMON_H__
#define __COMMON_H__

namespace SPlayer
{
    namespace Common
    {
        using namespace System;
        ref class LockGuard
        {
        public:
            LockGuard(System::Object ^obj) : object(obj), loocked(true)
            {
                if (object)
                {
                    System::Threading::Monitor::Enter(object);
                }
            }
            ~LockGuard()
            {
                unlock();
            }
            void unlock()
            {
                if (loocked)
                {
                    loocked = false;
                    if (object)
                    {
                        System::Threading::Monitor::Exit(object);
                    }
                }
            }
            //void lock()
            //{
            //    if (!loocked)
            //    {
            //        loocked = true;
            //        if (object)
            //        {
            //            System::Threading::Monitor::Exit(object);
            //        }
            //    }
            //}
        private:
            System::Object ^object;
            bool loocked = false;
        };

        ref class HandleGuard
        {
        public:
            HandleGuard(System::Object ^obj)
            {
                objects->AddLast(obj);
            }
            HandleGuard( ... array<System::Object ^> ^objs)
            {
                for each (auto obj in objs)
                {
                    objects->AddLast(obj);
                }
            }
            ~HandleGuard()
            {
                for each (auto object in objects)
                {
                    if (object)
                    {
                        delete object;
                        object = nullptr;
                    }
                }
                if (objects)
                {
                    delete objects;
                    objects = nullptr;
                }
            }
            void Add(... array<System::Object ^> ^objs)
            {
                for each (auto obj in objs)
                {
                    objects->AddLast(obj);
                }
            }
            void Add(System::Object ^obj)
            {
                objects->AddLast(obj);
            }
            void Remove(System::Object ^obj)
            {
                objects->Remove(obj);
            }
            void Delete(System::Object ^obj)
            {
                objects->Remove(obj);
                delete obj;
            }
        private:
            System::Collections::Generic::LinkedList<System::Object ^> ^objects = gcnew System::Collections::Generic::LinkedList<System::Object ^>;
        };

        class Function
        {
        public:
            static void InvokeSync(System::Delegate ^t, ... array<System::Object^>^ args)
            {
                if (t == nullptr)
                    return;

                for each (auto m in t->GetInvocationList())
                {
                    auto target = dynamic_cast<System::Windows::Forms::Form^>(m->Target);
                    if (target && target->InvokeRequired)
                    {
                        dynamic_cast<System::Windows::Forms::Form^>(m->Target)->BeginInvoke(t, args);
                    }
                    else
                    {
                        m->DynamicInvoke(args);
                    }
                }
            }
            template <class PtrType1, class PtrType2>
            static long long ptrOffset(PtrType1 p1, PtrType2 p2)
            {
                return reinterpret_cast<interior_ptr<char>>(p1)-reinterpret_cast<interior_ptr<char>>(p2);
            }

            static inline const char *stringToCStr(String ^str)
            {
                static const char *mem = nullptr;
                if (mem)
                {
                    System::Runtime::InteropServices::Marshal::ZeroFreeGlobalAllocAnsi((IntPtr)(void *)mem);
                    mem = nullptr;
                }
                return mem = (const char*)(char *)(void *)
                    System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(str);
            }

            static inline String ^cstrToString(const char *cstr)
            {
                return System::Runtime::InteropServices::Marshal::PtrToStringAnsi(
                    (IntPtr)(char *)cstr);
            }


            template <class T>
            ref class BindFirstHelper
            {
            public:
                BindFirstHelper(Action<T> ^func, T var) : func(func), var(var)
                { }
                void onAction()
                {
                    InvokeSync(func, var);
                }
            public:
                Action<T> ^func;
                T var;
            };

            template <class T>
            static Action ^bindFirst(Action<T> ^func, T var)
            {
                BindFirstHelper<T> ^helper = gcnew BindFirstHelper<T>(func, var);
                return gcnew Action(helper, &BindFirstHelper<T>::onAction);
            }

            static bool fileExist(String ^file)
            {
                try
                {
                    return IO::FileInfo(file).Exists;
                }
                catch (Exception ^)
                {
                }
                return false;
            }

            static bool dirExist(String ^dir)
            {
                try
                {
                    return IO::DirectoryInfo(dir).Exists;
                }
                catch (Exception ^)
                {
                }
                return false;
            }
        };
    }
}
#endif // __COMMON_H__